home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2004 #9
/
Amiga Plus CD - 2004 - No. 09.iso
/
amigaplus
/
games
/
wormwars
/
source
/
engine2.c
< prev
next >
Wrap
C/C++ Source or Header
|
2004-08-03
|
106KB
|
2,826 lines
// 1. INCLUDES -----------------------------------------------------------
#include "stdafx.h"
#include "diff.h"
#include "same.h"
#include "engine.h"
#include <stdlib.h> // abs()
// 2. DEFINES ------------------------------------------------------------
// 3. EXPORTED VARIABLES -------------------------------------------------
AGLOBAL UBYTE birdframes[BIRDFRAMES + 1] =
{ BIRD,
FIRSTBIRDFRAME,
FIRSTBIRDFRAME + 1,
FIRSTBIRDFRAME + 2,
FIRSTBIRDFRAME + 3
},
missileframes[4][MISSILEFRAMES + 1] =
{ { FIRSTMISSILE, // green (p1)
FIRSTMISSILEFRAME,
FIRSTMISSILEFRAME + 1,
FIRSTMISSILEFRAME + 2,
FIRSTMISSILEFRAME + 3,
FIRSTMISSILEFRAME + 4
},
{ FIRSTMISSILE + 1, // red (p2)
FIRSTMISSILEFRAME + 5,
FIRSTMISSILEFRAME + 6,
FIRSTMISSILEFRAME + 7,
FIRSTMISSILEFRAME + 8,
FIRSTMISSILEFRAME + 9
},
{ FIRSTMISSILE + 2, // blue (p3)
FIRSTMISSILEFRAME + 10,
FIRSTMISSILEFRAME + 11,
FIRSTMISSILEFRAME + 12,
FIRSTMISSILEFRAME + 13,
FIRSTMISSILEFRAME + 14,
},
{ FIRSTMISSILE + 3, // yellow (p4)
FIRSTMISSILEFRAME + 15,
FIRSTMISSILEFRAME + 16,
FIRSTMISSILEFRAME + 17,
FIRSTMISSILEFRAME + 18,
FIRSTMISSILEFRAME + 19
} },
bananaframes[4][BANANAFRAMES + 1] =
{ { FIRSTBANANA,
FIRSTBANANAFRAME + 0,
FIRSTBANANAFRAME + 1,
FIRSTBANANAFRAME + 2,
FIRSTBANANAFRAME + 3,
FIRSTBANANAFRAME + 4,
FIRSTBANANAFRAME + 5,
FIRSTBANANAFRAME + 6,
},
{ FIRSTBANANA + 1,
FIRSTBANANAFRAME + 7,
FIRSTBANANAFRAME + 8,
FIRSTBANANAFRAME + 9,
FIRSTBANANAFRAME + 10,
FIRSTBANANAFRAME + 11,
FIRSTBANANAFRAME + 12,
FIRSTBANANAFRAME + 13,
},
{ FIRSTBANANA + 2,
FIRSTBANANAFRAME + 14,
FIRSTBANANAFRAME + 15,
FIRSTBANANAFRAME + 16,
FIRSTBANANAFRAME + 17,
FIRSTBANANAFRAME + 18,
FIRSTBANANAFRAME + 19,
FIRSTBANANAFRAME + 20,
},
{ FIRSTBANANA + 3,
FIRSTBANANAFRAME + 21,
FIRSTBANANAFRAME + 22,
FIRSTBANANAFRAME + 23,
FIRSTBANANAFRAME + 24,
FIRSTBANANAFRAME + 25,
FIRSTBANANAFRAME + 26,
FIRSTBANANAFRAME + 27,
} };
// 4. IMPORTED VARIABLES -------------------------------------------------
// from engine1.c
IMPORT ABOOL banging,
enclosed;
IMPORT UBYTE field[MAXFIELDX + 1][MAXFIELDY + 1],
tailfield[MAXFIELDX + 1][MAXFIELDY + 1];
IMPORT SBYTE level,
numberx,
numbery,
number,
treasurer,
players,
levels,
reallevel;
IMPORT SWORD fieldx, fieldy,
secondsleft,
secondsperlevel;
IMPORT ULONG r;
IMPORT struct CreatureStruct creature[CREATURES + 1];
IMPORT struct MagnetStruct magnet[MAGNETS + 1];
IMPORT struct ObjectStruct object[LASTOBJECT + 1];
IMPORT struct ProtectorStruct protector[4][PROTECTORS + 1];
IMPORT struct TeleportStruct teleport[2];
IMPORT struct WormStruct worm[4];
IMPORT struct CreatureInfoStruct creatureinfo[SPECIES + 1];
// 5. MODULE VARIABLES ---------------------------------------------------
// 6. MODULE STRUCTURES --------------------------------------------------
MODULE struct
{ SBYTE deltax, deltay;
} thedogqueue[CREATURES + 1][DOGQUEUELIMIT + 1];
MODULE struct
{ SBYTE deltax, deltay;
} thewormqueue[4][WORMQUEUELIMIT + 1];
struct
{ SBYTE x, y, deltax, deltay;
ABOOL alive, moved, teleported, visible, reflected;
} bullet[9];
MODULE UBYTE eachtail[4][2][9][9] = {
{ { { GN_SE_NW, GN_SE_N, GN_SE_NE, // going NW (delta -1, -1)
GN_SE_W, WHATEVER, GN_SE_E, // (so starting from SE)
GN_SE_SW, GN_SE_S, GN_SE_NW
},
{ GN_S_NW, GN_S_N, GN_S_NE, // going N (delta 0, -1)
GN_S_W, WHATEVER, GN_S_E, // (so starting from S)
GN_S_SW, GN_S_N, GN_S_SE
},
{ GN_SW_NW, GN_SW_N, GN_SW_NE, // going NE (delta 0, 1)
GN_SW_W, WHATEVER, GN_SW_E, // (so starting from SW)
GN_SW_NE, GN_SW_S, GN_SW_SE
},
{ GN_E_NW, GN_E_N, GN_E_NE, // going W (delta -1, 0)
GN_E_W, WHATEVER, GN_E_W, // (so starting from E)
GN_E_SW, GN_E_S, GN_E_SE
},
{ GN_SE_NW, GN_S_N, GN_SW_NE, // going nowhere (delta 0, 0)
GN_E_W, WHATEVER, GN_W_E,
GN_NE_SW, GN_N_S, GN_NW_SE
},
{ GN_W_NW, GN_W_N, GN_W_NE, // going E (delta 1, 0)
GN_W_E, WHATEVER, GN_W_E, // (so starting from W)
GN_W_SW, GN_W_S, GN_W_SE
},
{ GN_NE_NW, GN_NE_N, GN_NE_NW, // going SW (delta -1, 1)
GN_NE_W, WHATEVER, GN_NE_E, // (so starting from NE)
GN_NE_SW, GN_NE_S, GN_NE_SE
},
{ GN_N_NW, GN_N_S, GN_N_NE, // going S (delta 0, 1)
GN_N_W, WHATEVER, GN_N_E, // (so starting from N)
GN_N_SW, GN_N_S, GN_N_SE
},
{ GN_NW_SE, GN_NW_N, GN_NW_NE, // going SE (delta 1, 1)
GN_NW_W, WHATEVER, GN_NW_E, // (so starting from NW)
GN_NW_SW, GN_NW_S, GN_NW_SE
} },
{ { GG_SE_NW, GG_SE_N, GG_SE_NE, // going NW (delta -1, -1)
GG_SE_W, WHATEVER, GG_SE_E, // (so starting from SE)
GG_SE_SW, GG_SE_S, GG_SE_NW
},
{ GG_S_NW, GG_S_N, GG_S_NE, // going N (delta 0, -1)
GG_S_W, WHATEVER, GG_S_E, // (so starting from S)
GG_S_SW, GG_S_N, GG_S_SE
},
{ GG_SW_NW, GG_SW_N, GG_SW_NE, // going NE (delta 0, 1)
GG_SW_W, WHATEVER, GG_SW_E, // (so starting from SW)
GG_SW_NE, GG_SW_S, GG_SW_SE
},
{ GG_E_NW, GG_E_N, GG_E_NE, // going W (delta -1, 0)
GG_E_W, WHATEVER, GG_E_W, // (so starting from E)
GG_E_SW, GG_E_S, GG_E_SE
},
{ GG_SE_NW, GG_S_N, GG_SW_NE, // going nowhere (delta 0, 0)
GG_E_W, WHATEVER, GG_W_E,
GG_NE_SW, GG_N_S, GG_NW_SE
},
{ GG_W_NW, GG_W_N, GG_W_NE, // going E (delta 1, 0)
GG_W_E, WHATEVER, GG_W_E, // (so starting from W)
GG_W_SW, GG_W_S, GG_W_SE
},
{ GG_NE_NW, GG_NE_N, GG_NE_SW, // going SW (delta -1, 1)
GG_NE_W, WHATEVER, GG_NE_E, // (so starting from NE)
GG_NE_SW, GG_NE_S, GG_NE_SE
},
{ GG_N_NW, GG_N_S, GG_N_NE, // going S (delta 0, 1)
GG_N_W, WHATEVER, GG_N_E, // (so starting from N)
GG_N_SW, GG_N_S, GG_N_SE
},
{ GG_NW_SE, GG_NW_N, GG_NW_NE, // going SE (delta 1, 1)
GG_NW_W, WHATEVER, GG_NW_E, // (so starting from NW)
GG_NW_SW, GG_NW_S, GG_NW_SE
} } },
{ { { RN_SE_NW, RN_SE_N, RN_SE_NE, // going NW (delta -1, -1)
RN_SE_W, WHATEVER, RN_SE_E, // (so starting from SE)
RN_SE_SW, RN_SE_S, RN_SE_NW,
},
{ RN_S_NW, RN_S_N, RN_S_NE, // going N (delta 0, -1)
RN_S_W, WHATEVER, RN_S_E, // (so starting from S)
RN_S_SW, RN_S_N, RN_S_SE
},
{ RN_SW_NW, RN_SW_N, RN_SW_NE, // going NE (delta 0, 1)
RN_SW_W, WHATEVER, RN_SW_E, // (so starting from SW)
RN_SW_NE, RN_SW_S, RN_SW_SE
},
{ RN_E_NW, RN_E_N, RN_E_NE, // going W (delta -1, 0)
RN_E_W, WHATEVER, RN_E_W, // (so starting from E)
RN_E_SW, RN_E_S, RN_E_SE
},
{ RN_SE_NW, RN_S_N, RN_SW_NE, // going nowhere (delta 0, 0)
RN_E_W, WHATEVER, RN_W_E,
RN_NE_SW, RN_N_S, RN_NW_SE
},
{ RN_W_NW, RN_W_N, RN_W_NE, // going E (delta 1, 0)
RN_W_E, WHATEVER, RN_W_E, // (so starting from W)
RN_W_SW, RN_W_S, RN_W_SE
},
{ RN_NE_NW, RN_NE_N, RN_NE_SW, // going SW (delta -1, 1)
RN_NE_W, WHATEVER, RN_NE_E, // (so starting from NE)
RN_NE_SW, RN_NE_S, RN_NE_SE
},
{ RN_N_NW, RN_N_S, RN_N_NE, // going S (delta 0, 1)
RN_N_W, WHATEVER, RN_N_E, // (so starting from N)
RN_N_SW, RN_N_S, RN_N_SE
},
{ RN_NW_SE, RN_NW_N, RN_NW_NE, // going SE (delta 1, 1)
RN_NW_W, WHATEVER, RN_NW_E, // (so starting from NW)
RN_NW_SW, RN_NW_S, RN_NW_SE
} },
{ { RG_SE_NW, RG_SE_N, RG_SE_NE, // going NW (delta -1, -1)
RG_SE_W, WHATEVER, RG_SE_E, // (so starting from SE)
RG_SE_SW, RG_SE_S, RG_SE_NW
},
{ RG_S_NW, RG_S_N, RG_S_NE, // going N (delta 0, -1)
RG_S_W, WHATEVER, RG_S_E, // (so starting from S)
RG_S_SW, RG_S_N, RG_S_SE
},
{ RG_SW_NW, RG_SW_N, RG_SW_NE, // going NE (delta 0, 1)
RG_SW_W, WHATEVER, RG_SW_E, // (so starting from SW)
RG_SW_NE, RG_SW_S, RG_SW_SE
},
{ RG_E_NW, RG_E_N, RG_E_NE, // going W (delta -1, 0)
RG_E_W, WHATEVER, RG_E_W, // (so starting from E)
RG_E_SW, RG_E_S, RG_E_SE
},
{ RG_SE_NW, RG_S_N, RG_SW_NE, // going nowhere (delta 0, 0)
RG_E_W, WHATEVER, RG_W_E,
RG_NE_SW, RG_N_S, RG_NW_SE
},
{ RG_W_NW, RG_W_N, RG_W_NE, // going E (delta 1, 0)
RG_W_E, WHATEVER, RG_W_E, // (so starting from W)
RG_W_SW, RG_W_S, RG_W_SE
},
{ RG_NE_NW, RG_NE_N, RG_NE_SW, // going SW (delta -1, 1)
RG_NE_W, WHATEVER, RG_NE_E, // (so starting from NE)
RG_NE_SW, RG_NE_S, RG_NE_SE
},
{ RG_N_NW, RG_N_S, RG_N_NE, // going S (delta 0, 1)
RG_N_W, WHATEVER, RG_N_E, // (so starting from N)
RG_N_SW, RG_N_S, RG_N_SE
},
{ RG_NW_SE, RG_NW_N, RG_NW_NE, // going SE (delta 1, 1)
RG_NW_W, WHATEVER, RG_NW_E, // (so starting from NW)
RG_NW_SW, RG_NW_S, RG_NW_SE
} } },
{ { { BN_NW_SE, BN_N_SE, BN_NE_SE, // going NW (delta -1, -1)
BN_W_SE, WHATEVER, BN_E_SE, // (so starting from SE)
BN_SW_SE, BN_S_SE, BN_NW_SE
},
{ BN_NW_S, BN_N_S, BN_NE_S, // going N (delta 0, -1)
BN_W_S, WHATEVER, BN_E_S, // (so starting from S)
BN_S_SW, BN_N_S, BN_S_SE
},
{ BN_NW_SW, BN_N_SW, BN_NE_SW, // going NE (delta 0, 1)
BN_W_SW, WHATEVER, BN_SW_E, // (so starting from SW)
BN_NE_SW, BN_S_SW, BN_SW_SE
},
{ BN_NW_E, BN_N_E, BN_E_NE, // going W (delta -1, 0)
BN_W_E, WHATEVER, BN_W_E, // (so starting from E)
BN_SW_E, BN_E_S, BN_E_SE
},
{ BN_NW_SE, BN_N_S, BN_NE_SW, // going nowhere (delta 0, 0)
BN_W_E, WHATEVER, BN_W_E,
BN_NE_SW, BN_N_S, BN_NW_SE
},
{ BN_W_NW, BN_N_W, BN_W_NE, // going E (delta 1, 0)
BN_W_E, WHATEVER, BN_W_E, // (so starting from W)
BN_W_SW, BN_W_S, BN_W_SE
},
{ BN_NW_NE, BN_N_NE, BN_NE_SW, // going SW (delta -1, 1)
BN_W_NE, WHATEVER, BN_E_NE, // (so starting from NE)
BN_NE_SW, BN_NE_S, BN_NE_SE
},
{ BN_N_NW, BN_N_S, BN_N_NE, // going S (delta 0, 1)
BN_N_W, WHATEVER, BN_N_E, // (so starting from N)
BN_N_SW, BN_N_S, BN_N_SE
},
{ BN_SW_SE, BN_N_NW, BN_NW_NE, // going SE (delta 1, 1)
BN_W_NW, WHATEVER, BN_NW_E, // (so starting from NW)
BN_NW_SW, BN_NW_S, BN_NW_SE
} },
{ { BG_NW_SE, BG_N_SE, BG_NE_SE, // going NW (delta -1, -1)
BG_W_SE, WHATEVER, BG_E_SE, // (so starting from SE)
BG_SW_SE, BG_S_SE, BG_NW_SE
},
{ BG_NW_S, BG_N_S, BG_NE_S, // going N (delta 0, -1)
BG_W_S, WHATEVER, BG_E_S, // (so starting from S)
BG_S_SW, BG_N_S, BG_S_SE
},
{ BG_NW_SW, BG_N_SW, BG_NE_SW, // going NE (delta 0, 1)
BG_W_SW, WHATEVER, BG_SW_E, // (so starting from SW)
BG_NE_SW, BG_S_SW, BG_SW_SE
},
{ BG_NE_E, BG_N_E, BG_NE_E, // going W (delta -1, 0)
BG_W_E, WHATEVER, BG_W_E, // (so starting from E)
BG_SW_E, BG_E_S, BG_E_SE
},
{ BG_NW_SE, BG_N_S, BG_NE_SW, // going nowhere (delta 0, 0)
BG_W_E, WHATEVER, BG_W_E,
BG_NE_SW, BG_N_S, BG_NW_SE
},
{ BG_NW_W, BG_N_W, BG_NE_W, // going E (delta 1, 0)
BG_W_E, WHATEVER, BG_W_E, // (so starting from W)
BG_W_SW, BG_W_S, BG_W_SE
},
{ BG_NW_NE, BG_N_NE, BG_NE_SW, // going SW (delta -1, 1)
BG_NE_W, WHATEVER, BG_NE_E, // (so starting from NE)
BG_NE_SW, BG_NE_S, BG_NE_SE
},
{ BG_N_NW, BG_N_S, BG_N_NE, // going S (delta 0, 1)
BG_N_W, WHATEVER, BG_N_E, // (so starting from N)
BG_N_SW, BG_N_S, BG_N_SE
},
{ BG_NW_SE, BG_N_NW, BG_NW_NE, // going SE (delta 1, 1)
BG_NW_W, WHATEVER, BG_NW_E, // (so starting from NW)
BG_NW_SW, BG_NW_S, BG_NW_SE
} } },
{ { { YN_NW_SE, YN_N_SE, YN_NE_SE, // going NW (delta -1, -1)
YN_W_SE, WHATEVER, YN_E_SE, // (so starting from SE)
YN_SW_SE, YN_S_SE, YN_NW_SE
},
{ YN_NW_S, YN_N_S, YN_NE_S, // going N (delta 0, -1)
YN_W_S, WHATEVER, YN_S_E, // (so starting from S)
YN_S_SW, YN_N_S, YN_S_SE
},
{ YN_NW_SW, YN_N_SW, YN_NE_SW, // going NE (delta 0, 1)
YN_W_SW, WHATEVER, YN_E_SW, // (so starting from SW)
YN_NE_SW, YN_S_SW, YN_SW_SE
},
{ YN_NW_E, YN_N_E, YN_NE_E, // going W (delta -1, 0)
YN_W_E, WHATEVER, YN_W_E, // (so starting from E)
YN_E_SW, YN_S_E, YN_E_SE
},
{ YN_NW_SE, YN_N_S, YN_NE_SW, // going nowhere (delta 0, 0)
YN_W_E, WHATEVER, YN_W_E,
YN_NE_SW, YN_N_S, YN_NW_SE
},
{ YN_NW_W, YN_N_W, YN_W_NE, // going E (delta 1, 0)
YN_W_E, WHATEVER, YN_W_E, // (so starting from W)
YN_W_SW, YN_W_S, YN_W_SE
},
{ YN_NW_NE, YN_N_NE, YN_NE_SW, // going SW (delta -1, 1)
YN_W_NE, WHATEVER, YN_NE_E, // (so starting from NE)
YN_NE_SW, YN_NE_S, YN_NE_SE
},
{ YN_N_NW, YN_N_S, YN_N_NE, // going S (delta 0, 1)
YN_N_W, WHATEVER, YN_N_E, // (so starting from N)
YN_N_SW, YN_N_S, YN_N_SE
},
{ YN_NW_SE, YN_N_NW, YN_NW_NE, // going SE (delta 1, 1)
YN_NW_W, WHATEVER, YN_NW_E, // (so starting from NW)
YN_NW_SW, YN_NW_S, YN_NW_SE
} },
{ { YG_NW_SE, YG_N_SE, YG_NE_SE, // going NW (delta -1, -1)
YG_W_SE, WHATEVER, YG_E_SE, // (so starting from SE)
YG_SW_SE, YG_S_SE, YG_NW_SE
},
{ YG_S_NW, YG_N_S, YG_S_NE, // going N (delta 0, -1)
YG_W_S, WHATEVER, YG_E_S, // (so starting from S)
YG_S_SW, YG_N_S, YG_S_SE
},
{ YG_NW_SW, YG_N_SW, YG_NE_SW, // going NE (delta 0, 1)
YG_W_SW, WHATEVER, YG_E_SW, // (so starting from SW)
YG_NE_SW, YG_S_SW, YG_SW_SE
},
{ YG_E_NW, YG_E_N, YG_E_NE, // going W (delta -1, 0)
YG_W_E, WHATEVER, YG_W_E, // (so starting from E)
YG_E_SW, YG_E_S, YG_E_SE
},
{ YG_NW_SE, YG_N_S, YG_NE_SW, // going nowhere (delta 0, 0)
YG_W_E, WHATEVER, YG_W_E,
YG_NE_SW, YG_N_S, YG_NW_SE
},
{ YG_W_NW, YG_N_W, YG_W_NE, // going E (delta 1, 0)
YG_W_E, WHATEVER, YG_W_E, // (so starting from W)
YG_W_SW, YG_W_S, YG_W_SE
},
{ YG_NW_NE, YG_N_NE, YG_NE_SW, // going SW (delta -1, 1)
YG_W_NE, WHATEVER, YG_E_NE, // (so starting from NE)
YG_NE_SW, YG_S_NE, YG_NE_SE
},
{ YG_N_NW, YG_N_S, YG_N_NE, // going S (delta 0, 1)
YG_N_W, WHATEVER, YG_E_N, // (so starting from N)
YG_N_SW, YG_N_S, YG_N_SE
},
{ YG_NW_SE, YG_N_NW, YG_NW_NE, // going SE (delta 1, 1)
YG_W_NW, WHATEVER, YG_E_NW, // (so starting from NW)
YG_NW_SW, YG_S_NW, YG_NW_SE
} } }
};
// 7. MODULE FUNCTIONS ---------------------------------------------------
MODULE void creaturebullet(SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE subspecies);
MODULE void creaturecreature(UBYTE which1, UBYTE which2);
MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y);
MODULE void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y);
MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay);
MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot);
MODULE void wormbullet(SBYTE player);
MODULE void choosediagonal(UBYTE which);
MODULE void chooseorthagonal(SBYTE* xx, SBYTE* yy);
MODULE void protectorloop1(SBYTE player);
MODULE void protectorloop2(SBYTE player);
MODULE void turncreature(UBYTE which);
// 8. CODE ---------------------------------------------------------------
AGLOBAL void createcreature(UBYTE species,
UBYTE which,
SBYTE x,
SBYTE y,
SBYTE deltax,
SBYTE deltay,
UBYTE player,
UBYTE subspecies
)
{ if (species != ORB)
{ creature[which].deltax = deltax;
creature[which].deltay = deltay;
}
if (species != CAMEL)
{ creature[which].subspecies = subspecies;
}
if (species == MISSILE_C)
{ creature[which].visible = FALSE;
} else creature[which].visible = TRUE;
/* This is something of a workaround to get around the problem where the
tail/glow that eg. a fish appears on is not restored to the correct
glow-image...
if (creatureinfo[species - FIRSTCREATURE].wall == TRUE)
{ creature[which].last = creature[which].oldlast = field[x][y];
} else */
creature[which].last = creature[which].oldlast = EMPTY;
creature[which].alive = TRUE;
creature[which].x = x;
creature[which].y = y;
creature[which].species = species;
creature[which].player = player;
creature[which].speed = creatureinfo[species - FIRSTCREATURE].speed;
creature[which].score = creatureinfo[species - FIRSTCREATURE].score;
switch(species)
{
case HORSE:
creature[which].dir = arand(7);
turncreature(which);
break;
case MONKEY:
creature[which].dir =
creature[which].pos = 0;
break;
case OCTOPUS:
creature[which].dir =
creature[which].pos = -1;
break;
case DOG:
creature[which].pos = -1;
creature[which].dormant = DORMANT; /* dormant */
break;
case ORB:
creature[which].deltax = (arand(1) * 2) - 1;
creature[which].deltay = (arand(1) * 2) - 1;
break;
case RAIN:
effect(FXBORN_RAIN);
break;
case CYCLONE_C:
effect(FXGET_CYCLONE);
break;
case MISSILE_C:
effect(FXBORN_MISSILE);
creature[which].frame = 0;
break;
case BIRD:
creature[which].frame = 0;
creature[which].dir = 1;
break;
case SPIDER:
creature[which].last = FROST;
break;
case OTTER:
if (x == 0)
{ creature[which].going = OTTER_DOWN;
creature[which].journey = OTTER_RIGHT;
} else
{ creature[which].going = OTTER_UP;
creature[which].journey = OTTER_LEFT;
}
creature[which].last =
creature[which].oldlast = STONE;
break;
case CAMEL:
creature[which].subspecies = arand(LASTOBJECT);
break;
case FRAGMENT:
if (creature[which].subspecies == BANANA)
{ creature[which].player = arand(3);
creature[which].score = POINTS_BANANA;
creature[which].frame = 0;
if (!arand(1))
{ creature[which].dir = 1;
} else
{ creature[which].dir = -1;
} }
break;
case BULL:
if (!arand(1))
{ creature[which].dir = 1;
draw(x, y, BULLRIGHT);
} else
{ creature[which].dir = -1;
draw(x, y, BULLLEFT);
}
field[x][y] = BULL;
break;
case RABBIT:
if (deltax == 1)
{ draw(x, y, RABBITRIGHT);
} else
{ // assert(deltax == -1);
draw(x, y, RABBITLEFT);
}
// no need to worry about .dir, it is not used for rabbits
field[x][y] = RABBIT;
break;
case FROG:
if (!arand(2))
{ creature[which].dir = 1;
draw(x, y, FROGRIGHT);
} else
{ creature[which].dir = -1;
draw(x, y, FROGLEFT);
}
field[x][y] = FROG;
break;
default:
break;
}
if (creature[which].visible)
{ drawcreature(which);
}
if (level > 5 && creature[which].speed >= 2)
creature[which].speed--;
if (level > 10 && creature[which].speed >= 2)
creature[which].speed--;
if (level > 15 && creature[which].speed >= 2)
creature[which].speed--;
if (level > 20 && creature[which].speed >= 2)
creature[which].speed--;
}
AGLOBAL void creatureloop(SBYTE which)
{ UBYTE bestdistance, c, i, distance, player;
SBYTE x, xx, xxx, xmin, xmax, frontx, rearx,
y, yy, yyy, ymin, ymax, fronty, reary;
FLAG done;
x = creature[which].x;
y = creature[which].y;
if (!valid(x, y)) // defensive programming
{ creature[which].alive = FALSE;
return;
/* TEXT temp1[SAYLIMIT + 1], temp2[8];
strcpy(temp1, "BAD CREATURE AT x: ");
stci_d(temp2, x);
strcat(temp1, temp2);
strcat(temp1, ", y: ");
stci_d(temp2, y);
strcat(temp1, temp2);
strcat(temp1, "!");
say(temp1, PURPLE);
draw(fieldx + 1, 0, creature[which].species); // indicates which creature
Delay(250);
clearkybd();
anykey(FALSE); */
}
/* decide whether and where to move */
switch(creature[which].species)
{
case BIRD:
if (creature[which].player == 255)
{ bestdistance = 255;
for (player = 0; player <= 3; player++)
{ if (worm[player].lives)
{ xx = abs(worm[player].x - x);
yy = abs(worm[player].y - y);
if (xx > yy)
distance = xx;
else distance = yy;
if (distance <= DISTANCE_BIRD && distance < bestdistance)
{ effect(FXBORN_BIRD);
bestdistance = distance;
creature[which].player = player;
} } } }
if (creature[which].player != 255) // if swooping
{ if (worm[creature[which].player].lives)
{ creature[which].deltax = bsign(worm[creature[which].player].x - x);
creature[which].deltay = bsign(worm[creature[which].player].y - y);
} else
{ creature[which].player = 255; // return to dormancy
creature[which].deltax = creature[which].deltay = 0;
} }
break;
case CAMEL:
xx = x + creature[which].deltax;
yy = y + creature[which].deltay;
if
( !arand(FREQ_CAMELTURN)
|| ((!creature[which].deltax) && (!creature[which].deltay))
|| !valid(xx, yy)
|| field[xx][yy] < FIRSTEMPTY
|| field[xx][yy] > LASTEMPTY
)
{ do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
c = field[x + xx][y + yy];
if (c >= FIRSTEMPTY && c <= LASTEMPTY)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
} else
{ creature[which].deltax = 0;
creature[which].deltay = 0;
} }
if
( (creature[which].deltax || creature[which].deltay)
&& (!arand(FREQ_CAMELDROP))
)
{ creature[which].last = creature[which].subspecies;
} else creature[which].last = EMPTY;
break;
case CLOUD:
if
( creature[which].x == 0
|| creature[which].x == fieldx
|| field[x + creature[which].deltax][y + creature[which].deltay] == METAL
|| field[x + creature[which].deltax][y + creature[which].deltay] == STONE
|| field[x + creature[which].deltax][y + creature[which].deltay] == WOOD
)
{ creature[which].deltax = -creature[which].deltax;
}
break;
case DOG:
/* remove a movement from the dog queue */
if (creature[which].dormant == CHASING)
{ if (creature[which].pos != -1)
{ creature[which].deltax = thedogqueue[which][0].deltax;
creature[which].deltay = thedogqueue[which][0].deltay;
if (--creature[which].pos != -1)
{ for (i = 0; i <= creature[which].pos; i++)
{ thedogqueue[which][i].deltax = thedogqueue[which][i + 1].deltax;
thedogqueue[which][i].deltay = thedogqueue[which][i + 1].deltay;
} } }
else creature[which].alive = FALSE;
}
break;
case FISH:
do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
c = field[x + xx][y + yy];
if
( c == SLIME
|| c == WOOD
|| c == STONE
|| c == METAL
|| (c >= FIRSTTAIL && c <= LASTTAIL)
|| (c >= FIRSTGLOW && c <= LASTGLOW)
)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
creature[which].last = creature[which].oldlast;
if (c >= FIRSTTAIL && c <= LASTTAIL)
{ creature[which].oldlast = c - FIRSTTAIL + FIRSTGLOW;
} else creature[which].oldlast = c;
} else
{ creature[which].deltax =
creature[which].deltay = 0;
}
break;
case GOOSE:
i = arand(3);
switch(i)
{
case 0:
creature[which].deltax = -1;
creature[which].deltay = 0;
break;
case 1:
creature[which].deltax = 1;
creature[which].deltay = 0;
break;
case 2:
creature[which].deltax = 0;
creature[which].deltay = -1;
break;
case 3:
creature[which].deltax = 0;
creature[which].deltay = 1;
break;
default:
// assert(0);
break;
}
break;
case HORSE:
if (!arand(FREQ_HORSETURN))
{ if (!arand(1))
{ if (creature[which].dir == 0)
{ creature[which].dir = 7;
} else
{ creature[which].dir--;
} }
else
{ if (creature[which].dir == 7)
{ creature[which].dir = 0;
} else
{ creature[which].dir++;
} }
turncreature(which);
}
break;
case KANGAROO:
creature[which].deltax = bsign(creature[which].deltax);
creature[which].deltay = bsign(creature[which].deltay);
if
( ((!creature[which].deltax) && (!creature[which].deltay))
|| !arand(FREQ_KANGAROOTURN)
)
{ do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
c = field[x + xx][y + yy];
if (c >= FIRSTEMPTY && c <= LASTEMPTY)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
} else
{ creature[which].deltax = 0;
creature[which].deltay = 0;
} }
else
{ c = field[xwrap(x + creature[which].deltax)][ywrap(y + creature[which].deltay)];
if (c < FIRSTEMPTY || c > LASTEMPTY)
{ c = field[xwrap(x + (creature[which].deltax * 2))][ywrap(y + (creature[which].deltay * 2))];
if (c >= FIRSTEMPTY && c <= LASTEMPTY)
{ creature[which].deltax *= 2;
creature[which].deltay *= 2;
} else
{ c = field[xwrap(x - creature[which].deltax)][ywrap(y - creature[which].deltay)];
if (c >= FIRSTEMPTY && c <= LASTEMPTY)
{ creature[which].deltax = -creature[which].deltax;
creature[which].deltay = -creature[which].deltay;
} else
{ creature[which].deltax =
creature[which].deltay = 0;
} } } }
break;
case MISSILE_C:
bestdistance = 255;
for (player = 0; player <= 3; player++)
{ if (creature[which].player != player && worm[player].lives)
{ xx = abs(worm[player].x - x);
yy = abs(worm[player].y - y);
if (xx < yy)
{ distance = xx;
} else distance = yy;
if (distance < bestdistance)
{ bestdistance = distance;
creature[which].deltax = bsign(worm[player].x - x);
creature[which].deltay = bsign(worm[player].y - y);
} }
for (i = 0; i <= CREATURES; i++)
{ if
( creature[i].alive
&& which != i
&& creature[i].player != player
)
{ xx = abs(creature[i].x - x);
yy = abs(creature[i].y - y);
if (xx < yy)
{ distance = xx;
} else distance = yy;
if (distance < bestdistance)
{ bestdistance = distance;
creature[which].deltax = bsign(creature[i].x - x);
creature[which].deltay = bsign(creature[i].y - y);
} } } }
if (bestdistance == 255)
{ creature[which].alive = FALSE;
change(x, y, EMPTY);
}
break;
case MONKEY:
creature[which].pos += creature[which].dir;
if (creature[which].pos == 0) // monkey never stops moving
{ choosediagonal(which);
creature[which].dir = 1;
} elif (creature[which].pos == 5)
{ creature[which].deltax = -creature[which].deltax;
creature[which].deltay = -creature[which].deltay;
creature[which].dir = -1;
}
break;
case ORB:
frontx = xwrap(x + creature[which].deltax); /* look in front */
fronty = ywrap(y + creature[which].deltay);
rearx = xwrap(x - creature[which].deltax); /* look behind */
reary = ywrap(y - creature[which].deltay);
if (bouncecreature(which, frontx, fronty))
{ bounceoffcreature(which, frontx, fronty);
xx = -creature[which].deltax; /* default bounce angle is 180° */
yy = -creature[which].deltay;
if (!bouncecreature(which, frontx, reary))
{ if (bouncecreature(which, rearx, fronty))
{ bounceoffcreature(which, rearx, fronty);
xx = creature[which].deltax;
} }
elif (!bouncecreature(which, rearx, fronty))
{ bounceoffcreature(which, rearx, fronty);
yy = creature[which].deltay;
}
creature[which].deltax = xx;
creature[which].deltay = yy;
}
break;
case OTTER:
if (secondsleft)
{ return;
}
if (creature[which].journey == OTTER_RIGHT)
{ switch(creature[which].going)
{
case OTTER_DOWN:
if (creature[which].y == fieldy)
{ if (creature[which].x == fieldx)
{ creature[which].journey = OTTER_LEFT;
creature[which].going = OTTER_UP;
} else
{ creature[which].going = OTTER_RIGHT;
creature[which].then = OTTER_UP;
} }
break;
case OTTER_RIGHT:
creature[which].going = creature[which].then;
break;
case OTTER_UP:
if (creature[which].y == 0)
{ if (creature[which].x == fieldx)
{ creature[which].journey = OTTER_LEFT;
creature[which].going = OTTER_DOWN;
} else
{ creature[which].going = OTTER_RIGHT;
creature[which].then = OTTER_DOWN;
} }
break;
default:
break;
} }
else
{ // assert(creature[which].journey == OTTER_LEFT);
switch(creature[which].going)
{
case OTTER_DOWN:
if (creature[which].y == fieldy)
{ if (creature[which].x == 0)
{ creature[which].journey = OTTER_RIGHT;
creature[which].going = OTTER_UP;
} else
{ creature[which].going = OTTER_LEFT;
creature[which].then = OTTER_UP;
} }
break;
case OTTER_LEFT:
creature[which].going = creature[which].then;
break;
case OTTER_UP:
if (creature[which].y == 0)
{ if (creature[which].x == 0)
{ creature[which].journey = OTTER_RIGHT;
creature[which].going = OTTER_DOWN;
} else
{ creature[which].going = OTTER_LEFT;
creature[which].then = OTTER_DOWN;
} }
break;
default:
// assert(0);
break;
} }
if (creature[which].going == OTTER_RIGHT)
{ creature[which].deltax = 1;
creature[which].deltay = 0;
} elif (creature[which].going == OTTER_LEFT)
{ creature[which].deltax = -1;
creature[which].deltay = 0;
} elif (creature[which].going == OTTER_UP)
{ creature[which].deltax = 0;
creature[which].deltay = -1;
} elif (creature[which].going == OTTER_DOWN)
{ creature[which].deltax = 0;
creature[which].deltay = 1;
}
break;
case ANT:
do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
if (xx == 0 && yy == 0)
{ if (valid(x + creature[which].deltax, y + creature[which].deltay))
{ xx = creature[which].deltax;
yy = creature[which].deltay;
} else
{ xx = -creature[which].deltax;
yy = -creature[which].deltay;
} }
creature[which].deltax = xx;
creature[which].deltay = yy;
break;
case CYCLONE_C:
/* Cyclones have a slight upwards drift.
Higher values of WEIGHT make them less buoyant. */
creature[which].deltax = arand(2) - 1;
if (!arand(WEIGHT))
creature[which].deltay = arand(1) - 1;
else creature[which].deltay = arand(2) - 1;
break;
case RABBIT:
xx = x + creature[which].deltax;
done = FALSE;
do
{ if (!valid(xx, y))
{ creature[which].alive = FALSE;
change(x, y, EMPTY);
done = TRUE;
} elif
( field[xx][y] <= LASTOBJECT
|| (field[xx][y] >= FIRSTEMPTY && field[xx][y] <= LASTEMPTY)
)
{ creature[which].x = xx;
done = TRUE;
} else
{ xx += creature[which].deltax;
} }
while (!done);
break;
case MOUSE:
bestdistance = 255;
if (x - DISTANCE_MOUSE < 0)
{ xmin = 0;
} else xmin = x - DISTANCE_MOUSE;
if (x + DISTANCE_MOUSE > fieldx)
{ xmax = fieldx;
} else xmax = x + DISTANCE_MOUSE;
if (y - DISTANCE_MOUSE < 0)
{ ymin = 0;
} else ymin = y - DISTANCE_MOUSE;
if (y + DISTANCE_MOUSE > fieldy)
{ ymax = fieldy;
} else ymax = y + DISTANCE_MOUSE;
for (xx = xmin; xx <= xmax; xx++)
{ for (yy = ymin; yy <= ymax; yy++)
{ // assert(valid(xx, yy));
if (field[xx][yy] <= LASTOBJECT)
{ xxx = abs(xx - x);
yyy = abs(yy - y);
if (xxx < yyy)
{ distance = xxx;
} else distance = yyy;
if (distance < bestdistance)
{ bestdistance = distance;
creature[which].deltax = bsign(xx - x);
creature[which].deltay = bsign(yy - y);
} } } }
if (bestdistance == 255)
{ creature[which].deltax =
creature[which].deltay = 0;
}
break;
case SNAIL:
xx = creature[which].deltax;
yy = creature[which].deltay;
if
( (!valid(x + xx, y + yy))
|| (xx == 0 && yy == 0)
|| (field[x + xx][y + yy] > LASTOBJECT && (field[x + xx][y + yy] < FIRSTEMPTY || field[x + xx][y + yy] > LASTEMPTY))
)
{ do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
if
( field[x + xx][y + yy] <= LASTOBJECT
|| (field[x + xx][y + yy] >= FIRSTEMPTY && field[x + xx][y + yy] <= LASTEMPTY)
)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
} else
{ creature[which].deltax = 0;
creature[which].deltay = 0;
} }
break;
case SPIDER:
xx = creature[which].deltax;
yy = creature[which].deltay;
if
( (!valid(x + xx, y + yy))
|| (xx == 0 && yy == 0)
|| (field[x + xx][y + yy] > LASTOBJECT && (field[x + xx][y + yy] < FIRSTEMPTY || field[x + xx][y + yy] > LASTEMPTY))
|| (!arand(FREQ_SPIDERTURN))
)
{ do
{ xx = arand(2) - 1;
yy = arand(2) - 1;
} while (!valid(x + xx, y + yy));
if
( field[x + xx][y + yy] <= LASTOBJECT
|| (field[x + xx][y + yy] >= FIRSTEMPTY && field[x + xx][y + yy] <= LASTEMPTY)
|| field[x + xx][y + yy] == FROST // so that spiders can traverse their own webs
)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
} else
{ creature[which].deltax = 0;
creature[which].deltay = 0;
} }
break;
case FROG:
if (creature[which].deltax != 0 || creature[which].deltay != 0)
{ creature[which].deltax = 0;
creature[which].deltay = 0;
} elif (creature[which].dormant == 0 && !arand(FREQ_FROGMOVE))
{ xx = arand(6) - 3;
yy = arand(6) - 3;
if
( (xx != 0 || yy != 0)
&& valid(x + xx, y + yy)
&& field[x + xx][y + yy] >= FIRSTEMPTY
&& field[x + xx][y + yy] <= LASTEMPTY
)
{ creature[which].deltax = xx;
creature[which].deltay = yy;
if (!arand(1))
{ creature[which].dir = -1;
} else
{ creature[which].dir = 1;
} } }
break;
case SALAMANDER:
// this is a workaround for a very strange bug
choosediagonal(which);
break;
default: // octopus, giraffe, fragment, bull
break;
}
/* now move */
if (creature[which].deltax || creature[which].deltay)
{ if (creature[which].visible)
{ /* erase previous image */
if
( (creature[which].last >= FIRSTTAIL && creature[which].last <= LASTTAIL)
|| (creature[which].last >= FIRSTGLOW && creature[which].last <= LASTGLOW)
)
{ field[x][y] = creature[which].last;
if (tailfield[x][y] < FIRSTMAGIC)
{ drawtail(x, y, tailfield[x][y] + ((creature[which].last - FIRSTGLOW) * SECONDMAGIC) + FIRSTMAGIC);
} else
{ drawtail(x, y, tailfield[x][y] + ((creature[which].last - FIRSTGLOW) * SECONDMAGIC));
} }
else
{ change(x, y, creature[which].last);
}
if (creature[which].species == OTTER)
{ creature[which].last = STONE;
} elif (creature[which].species == SPIDER)
{ creature[which].last = FROST;
} elif (creature[which].species == GOOSE)
{ creature[which].last = GOLD;
} else
{ creature[which].last = EMPTY;
} }
if (creature[which].alive)
{ creature[which].x += creature[which].deltax;
creature[which].y += creature[which].deltay;
if
( creature[which].species == ORB
|| creature[which].species == HORSE
|| creature[which].species == MONKEY
)
{ creature[which].x = xwrap(creature[which].x);
creature[which].y = ywrap(creature[which].y);
} elif (!valid(creature[which].x, creature[which].y))
{ creature[which].alive = FALSE;
} } }
creature[which].visible = TRUE;
x = creature[which].x;
y = creature[which].y;
/* Collision detection. */
if
( creature[which].alive
&& creature[which].species != FISH
&& creature[which].species != GIRAFFE
&& (creature[which].deltax || creature[which].deltay)
)
{ c = field[x][y];
if (c >= FIRSTHEAD && c <= LASTHEAD)
{ wormcreature(c - FIRSTHEAD, which);
} elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
{ protcreature(c - FIRSTPROTECTOR, which);
} elif (c >= FIRSTTAIL && c <= LASTTAIL)
{ ;
} elif
( (c >= FIRSTNUMBER && c <= LASTNUMBER)
|| (c >= FIRSTGRAVE && c <= LASTGRAVE )
|| c == FROGTONGUE
|| c == START
)
{ creature[which].alive = FALSE;
} elif (c >= FIRSTCREATURE)
{ i = whichcreature(x, y, c, which);
creaturecreature(which, i);
} elif
( c == METAL
|| c == STONE
|| c == WOOD
)
{ if (!creatureinfo[creature[which].species - FIRSTCREATURE].wall)
{ if (creature[which].species == FRAGMENT && c == METAL)
{ effect(FXUSE_ARMOUR);
reflect(which);
} elif
( creature[which].species != OTTER
&& creature[which].species != CYCLONE_C
&& creature[which].species != ANT
&& creature[which].species != MISSILE_C
)
{ creature[which].alive = FALSE;
} } }
elif (c == TELEPORT)
{ i = whichteleport(x, y);
if (blockedtel(i, creature[which].deltax, creature[which].deltay))
creature[which].alive = FALSE;
else
{ effect(FXUSE_TELEPORT);
creature[which].x = teleport[partner(i)].x + creature[which].deltax;
creature[which].y = teleport[partner(i)].y + creature[which].deltay;
if (creature[which].species == ORB)
{ creature[which].x = xwrap(creature[which].x);
creature[which].y = ywrap(creature[which].y);
} else
{ if (!(valid(creature[which].x, creature[which].y)))
creature[which].alive = FALSE;
if (creature[which].species == FRAGMENT)
creature[which].last = SILVER;
} } }
elif (c <= LASTOBJECT && creature[which].species != MOUSE)
{ switch (c)
{
case MINIBOMB:
drawcreature(which);
bombblast(ORB, which, x, y, FALSE);
break;
case SUPERBOMB:
drawcreature(which);
bombblast(ORB, which, x, y, TRUE);
break;
case PROTECTOR:
effect(FXGET_OBJECT);
for (player = 0; player <= 3; player++)
{ if (worm[player].lives)
{ for (i = 0; i <= PROTECTORS; i++)
{ if (protector[player][i].alive)
{ protector[player][i].alive = FALSE;
if (protector[player][i].visible)
{ change(protector[player][i].x, protector[player][i].y, EMPTY);
} } } } }
break;
case MISSILE_O:
effect(FXGET_OBJECT);
for (i = 0; i <= CREATURES; i++)
{ if (creature[i].alive && creature[i].species == MISSILE_C)
{ creature[i].alive = FALSE;
change(x, y, EMPTY);
} }
break;
case MULTIPLIER:
effect(FXGET_OBJECT);
for (player = 0; player <= 3; player++)
{ if (worm[player].lives)
{ worm[player].multi = 1;
stat(player, BONUS);
} }
break;
case AFFIXER:
effect(FXGET_OBJECT);
for (player = 0; player <= 3; player++)
if (worm[player].lives)
{ worm[player].affixer = FALSE;
icon(player, AFFIXER);
}
break;
case REMNANTS:
effect(FXGET_OBJECT);
for (player = 0; player <= 3; player++)
if (worm[player].lives)
{ worm[player].remnants = FALSE;
icon(player, REMNANTS);
}
break;
case SIDESHOT:
effect(FXGET_POWERUP);
for (player = 0; player <= 3; player++)
if (worm[player].lives)
{ worm[player].sideshot = FALSE;
icon(player, SIDESHOT);
}
break;
case MAGNET:
effect(FXGET_OBJECT);
for (i = 0; i <= MAGNETS; i++)
if (magnet[i].alive)
magnet[i].alive = FALSE;
break;
case PUSHER:
effect(FXGET_OBJECT);
for (i = 0; i <= 3; i++)
if (worm[i].lives && worm[i].pusher)
{ worm[i].pusher = FALSE;
icon(i, PUSHER);
}
break;
case ENCLOSER:
effect(FXGET_OBJECT);
for (i = 0; i <= 3; i++)
{ if (worm[i].lives && worm[i].encloser)
{ worm[i].encloser = FALSE;
icon(i, ENCLOSER);
} }
break;
case GLOW:
effect(FXGET_OBJECT);
for (xx = 0; xx <= fieldx; xx++)
for (yy = 0; yy <= fieldy; yy++)
if (field[xx][yy] >= FIRSTGLOW && field[xx][yy] <= LASTGLOW)
change(xx, yy, EMPTY);
break;
case SWITCHER:
effect(FXGET_OBJECT);
for (xx = 0; xx <= fieldx; xx++)
for (yy = 0; yy <= fieldy; yy++)
if (field[xx][yy] >= FIRSTTAIL && field[xx][yy] <= LASTTAIL)
change(xx, yy, WOOD);
break;
case GROWER:
effect(FXGET_GROWER);
for (xx = 0; xx <= fieldx; xx++)
for (yy = 0; yy <= fieldy; yy++)
if (field[xx][yy] == WOOD)
for (xxx = xx - 1; xxx <= xx + 1; xxx++)
for (yyy = yy - 1; yyy <= yy + 1; yyy++) if (valid(xxx, yyy) && field[xxx][yyy] == EMPTY)
field[xxx][yyy] = TEMPWOOD;
for (xx = 0; xx <= fieldx; xx++)
for (yy = 0; yy <= fieldy; yy++)
if (field[xx][yy] == TEMPWOOD)
change(xx, yy, WOOD);
break;
case AUTOJUMP:
effect(FXGET_OBJECT);
for (player = 0; player <= 3; player++)
if (worm[player].lives)
{ worm[player].autojump = FALSE;
icon(player, AUTOJUMP);
}
break;
case CUTTER:
effect(FXGET_OBJECT);
for (i = 0; i <= 3; i++)
if (worm[i].lives && worm[i].cutter)
{ worm[i].cutter = 0;
icon(i, CUTTER);
}
break;
default:
effect(FXGET_OBJECT);
creature[which].speed = speedup(creature[which].speed, FALSE);
break;
} } }
x = creature[which].x; // These are refreshed in case a
y = creature[which].y; // fragment has been reflected.
if
( creature[which].alive
&& creature[which].visible
&& (creature[which].deltax || creature[which].deltay)
)
{ drawcreature(which);
}
if (creature[which].alive)
{ /* decide whether to fire */
switch(creature[which].species)
{
case CLOUD:
if (!arand(FREQ_CLOUDFIRE))
{ creaturebullet(x, y, 0, -1, FRAGMENT);
}
if (!arand(FREQ_CLOUDRAIN))
{ if (creature[which].y != fieldy)
{ c = field[x][y + 1];
if (c >= FIRSTEMPTY && c <= LASTEMPTY)
{ for (i = 0; i <= CREATURES; i++)
{ if (!creature[i].alive)
{ createcreature(RAIN, i, x, y + 1, 0, 1, (UBYTE) ((r / 16) % 4), 0);
break;
} } } } }
break;
case KANGAROO:
if (!arand(FREQ_KANGAROOFIRE))
{ creaturebullet(x, y, -1, -1, FRAGMENT);
creaturebullet(x, y, 1, -1, FRAGMENT);
creaturebullet(x, y, -1, 1, FRAGMENT);
creaturebullet(x, y, 1, 1, FRAGMENT);
}
break;
case MONKEY:
if (creature[which].pos == 5)
{ chooseorthagonal(&xx, &yy);
creaturebullet(x, y, xx, yy, BANANA);
}
break;
case OCTOPUS:
if (creature[which].dir == -1)
{ if (!arand(FREQ_OCTOPUSFIRE))
{ creature[which].dir = arand(7);
if (arand(1))
{ creature[which].tonguedir = 1;
} else
{ creature[which].tonguedir = -1;
}
creature[which].pos = -1;
} }
elif (!arand(FREQ_OCTOPUSSPIN))
{ for (i = 0; i <= CREATURES; i++)
{ if
( creature[i].alive
&& creature[i].species == OCTOPUS
&& creature[i].dir >= 0
)
{ for (i = 0; i <= CREATURES; i++)
{ if (!creature[i].alive)
{ switch(creature[which].dir)
{
case 0:
xx = 0;
yy = -1;
break;
case 1:
xx = 1;
yy = -1;
break;
case 2:
xx = 1;
yy = 0;
break;
case 3:
xx = 1;
yy = 1;
break;
case 4:
xx = 0;
yy = 1;
break;
case 5:
xx = -1;
yy = 1;
break;
case 6:
xx = -1;
yy = 0;
break;
case 7:
xx = -1;
yy = -1;
break;
default:
// assert(0);
xx = yy = 0; // to avoid spurious warnings
break;
}
xxx = x + xx;
yyy = y + yy;
if (valid(xxx, yyy))
{ effect(FXBORN_FRAGMENT);
createcreature(FRAGMENT, i, xxx, yyy, xx, yy, 255, FRAGMENT);
}
if (++creature[which].pos == 8)
{ creature[which].pos = -1;
} else
{ if (creature[which].dir == 7 && creature[which].tonguedir == 1)
{ creature[which].dir = 0;
} elif (creature[which].dir == 0 && creature[which].tonguedir == -1)
{ creature[which].dir = 7;
} else
{ creature[which].dir += creature[which].tonguedir;
} }
break;
} } } } }
break;
case SALAMANDER:
if (!arand(FREQ_SALAMANDERFIRE))
{ chooseorthagonal(&xx, &yy);
creaturebullet(x, y, xx, yy, FRAGMENT);
}
break;
case FROG:
if (creature[which].dormant == 0)
{ if (!arand(FREQ_FROGFIRE))
{ creature[which].dormant = 1;
creature[which].tonguedir = 1;
creature[which].tonguex = x;
if (creature[which].dir == -1)
{ draw(x, y, FROGMOUTHLEFT);
} else
{ // assert(creature[which].dir == 1);
draw(x, y, FROGMOUTHRIGHT);
} } }
else
{ creature[which].dormant += creature[which].tonguedir;
if (creature[which].tonguedir == 1)
{ if (valid(creature[which].tonguex + creature[which].dir, y))
{ c = field[creature[which].tonguex + creature[which].dir][y];
if
( c != TELEPORT
&& c != METAL
&& c != STONE
&& c != WOOD
&& (c < FIRSTPROTECTOR || c > LASTPROTECTOR)
)
{ creature[which].tonguex += creature[which].dir;
if (c >= FIRSTCREATURE)
{ creature[whichcreature(creature[which].tonguex, y, c, which)].alive = FALSE;
change(creature[which].tonguex, y, FROGTONGUE);
} elif (c >= FIRSTHEAD && c <= LASTHEAD && worm[c - FIRSTHEAD].armour == 0)
{ worm[c - FIRSTHEAD].cause = FROG;
worm[c - FIRSTHEAD].alive = FALSE;
worm[c - FIRSTHEAD].victor = -1;
} else
{ change(creature[which].tonguex, y, FROGTONGUE);
} }
else
{ creature[which].tonguedir = -1;
} }
else
{ creature[which].tonguedir = -1;
} }
else
{ // assert(creature[which].tonguedir == -1);
if (creature[which].dormant > 1)
{ if (field[creature[which].tonguex][y] == FROGTONGUE)
{ change(creature[which].tonguex, y, EMPTY);
}
creature[which].tonguex -= creature[which].dir;
} else
{ if (creature[which].dir == -1)
{ draw(x, y, FROGLEFT);
} else
{ // assert(creature[which].dir == 1);
draw(x, y, FROGRIGHT);
} } } }
break;
default:
// rabbits, snails, spiders, etc.
// ie. creatures which do not fire
break;
} } }
MODULE void creaturebullet(SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE subspecies)
{ UBYTE i, c;
for (i = 0; i <= CREATURES; i++)
{ if (!creature[i].alive)
{ if (valid(x + deltax, y + deltay))
{ c = field[x + deltax][y + deltay];
if
( (c >= FIRSTEMPTY && c <= LASTEMPTY)
|| (c >= FIRSTTAIL && c <= LASTTAIL)
)
{ effect(FXBORN_FRAGMENT);
createcreature(FRAGMENT, i, x + deltax, y + deltay, deltax, deltay, 255, subspecies);
} }
break;
} } }
AGLOBAL void wormkillcreature(UBYTE player, UBYTE which, FLAG vampirism)
{ FLAG novampirism = FALSE;
/* rain and bananas are ineligible for vampirism
if (which == 255)
{ say("Attempted to kill invalid creature!", PURPLE);
Delay(250);
clearkybd();
anykey(FALSE);
}
return; */
if (creature[which].species == BANANA)
{ if (creature[which].player == player)
{ worm[player].lives += 2;
} else
{ worm[player].lives++;
}
stat(player, MINIHEALER);
}
if
( creature[which].species == RAIN
|| ( creature[which].species == FRAGMENT
&& creature[which].subspecies == BANANA
) )
{ novampirism = TRUE;
if (creature[which].player == player)
{ wormscore(player, creature[which].score * 2);
} else
{ wormscore(player, creature[which].score);
} }
else
{ wormscore(player, creature[which].score);
}
creature[which].alive = FALSE;
if (worm[player].lives && vampirism && !novampirism)
{ worm[player].lives++;
stat(player, MINIHEALER);
}
if (creature[which].species == FRAGMENT)
{ if (creature[which].subspecies == BANANA)
{ effect(FXGET_GROWER);
} else
{ // assert(creature[which].subspecies == FRAGMENT);
effect(FXUSE_ARMOUR);
} }
elif (creature[which].species == RAIN)
{ effect(FXGET_RAIN);
} }
AGLOBAL void protcreature(UBYTE player, UBYTE which)
{ /* Handles collisions between protectors and creatures. */
switch(creature[which].species)
{
case FRAGMENT:
effect(FXBORN_PROTECTOR);
if (creature[which].subspecies == BANANA)
{ wormkillcreature(player, which, TRUE);
} else
{ // assert(creature[which].subspecies == FRAGMENT);
reflect(which);
}
break;
case MISSILE_C:
if (player != creature[which].player)
{ effect(FXBORN_PROTECTOR);
wormkillcreature(player, which, TRUE);
} else creature[which].visible = FALSE;
break;
default:
effect(FXBORN_PROTECTOR);
wormkillcreature(player, which, TRUE);
break;
} }
AGLOBAL void wormcreature(UBYTE player, UBYTE which)
{ SBYTE xx, yy;
/* Handles collisions between worms and creatures. */
if (creature[which].species == GIRAFFE)
{ xx = worm[player].x - (worm[player].deltax * DISTANCE_GIRAFFE);
yy = worm[player].y - (worm[player].deltay * DISTANCE_GIRAFFE);
if
( valid(xx, yy)
&& !blockedsquare(xx, yy)
)
{ worm[player].deltax = -worm[player].deltax;
worm[player].deltay = -worm[player].deltay;
worm[player].x = xx;
worm[player].y = yy;
if (!worm[player].armour)
{ worm[player].alive = FALSE;
worm[player].cause = GIRAFFE;
worm[player].victor = -1;
}
return;
} }
if
( creature[which].species == DOG
&& creature[which].dormant == DORMANT
)
{ effect(FXBORN_DOG);
creature[which].dormant = AWAKENING;
creature[which].player = player;
worm[player].last = DOG;
return;
}
if
( creature[which].species == MISSILE_C
&& creature[which].player == player
)
{ creature[which].visible = FALSE;
return;
}
if
( creature[which].species == FRAGMENT
&& creature[which].subspecies == FRAGMENT
&& worm[player].armour
)
{ effect(FXUSE_ARMOUR);
if (creature[which].species == FRAGMENT)
{ reflect(which);
}
return;
}
wormkillcreature(player, which, TRUE);
if (creature[which].species == RAIN)
{ return;
}
if
( creature[which].species == FRAGMENT
&& creature[which].subspecies == BANANA
)
{ return;
}
if (worm[player].armour)
{ effect(FXUSE_ARMOUR);
} elif (creature[which].player != player)
{ if (creature[which].species == MISSILE_C)
{ worm[player].cause = FIRSTMISSILE + creature[which].player;
} else
{ worm[player].cause = creature[which].species;
}
worm[player].victor = creature[which].player;
worm[player].alive = FALSE;
} }
MODULE void creaturecreature(UBYTE which1, UBYTE which2)
{ if
( creature[which1].species == MISSILE_C
&& creature[which2].species != MISSILE_C
)
{ wormkillcreature(creature[which1].player, which2, TRUE);
} elif
( creature[which1].species != MISSILE_C
&& creature[which2].species == MISSILE_C
)
{ wormkillcreature(creature[which2].player, which1, TRUE);
} else
{ creature[which1].alive =
creature[which2].alive = FALSE;
change(creature[which1].x, creature[which1].y, BONUS);
} }
MODULE void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y)
{ if
( field[x][y] >= FIRSTCREATURE
&& creatureinfo[field[x][y] - FIRSTCREATURE].wall
)
{ creature[whichcreature(x, y, field[x][y], which)].alive = FALSE;
change(x, y, BONUS);
} }
MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y)
{ if
( field[x][y] == METAL
|| field[x][y] == STONE
|| field[x][y] == WOOD
|| (field[x][y] >= FIRSTCREATURE && creatureinfo[field[x][y] - FIRSTCREATURE].wall)
|| (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
|| (field[x][y] >= FIRSTGLOW && field[x][y] <= LASTGLOW)
)
{ return TRUE;
} else
{ return FALSE;
} }
AGLOBAL UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception)
{ UBYTE i;
for (i = 0; i <= CREATURES; i++)
{ if
( creature[i].alive
&& creature[i].x == x
&& creature[i].y == y
&& creature[i].species == species
&& i != exception
)
{ return i;
} }
/* say("Attempted to find invalid creature!", PURPLE);
Delay(250);
clearkybd();
anykey(FALSE); */
return 255; /* error code */
}
AGLOBAL void wormloop(SBYTE player)
{ SBYTE bestx = 0, besty = 0, // to avoid spurious warnings
dirx, diry, i, j, x, y, index1, index2;
SWORD bestgood, good;
UBYTE c;
/* Amiga worm control
Remove a keystroke from the worm queue
Move worm (and add a keystroke to the dog queue)
Check for enclosure
Move protectors
Collision detection
AI: Amiga worm control.
Worm checks ahead, left and right one square. Assigns opinions
to those three choices and then takes the appropriate one.
Things which slow the worm down are doubly feared; this is to avoid
endless ramming situations. */
if (worm[player].control == AMIGA)
{ if (!arand(50))
wormqueue(player, arand(2) - 1, arand(2) - 1);
else
{ bestgood = -128;
for (i = 0; i <= 8; i++)
{ switch(i % 3)
{
case 0:
dirx = -1;
break;
case 1:
dirx = 0;
break;
case 2:
dirx = 1;
break;
default:
// assert(0);
break;
}
switch(i / 3)
{
case 0:
diry = -1;
break;
case 1:
diry = 0;
break;
case 2:
diry = 1;
break;
default:
// assert(0);
break;
}
if
( ( dirx == -worm[player].deltax
&& diry == -worm[player].deltay
)
|| ( dirx == 0
&& diry == 0
) )
{ continue;
}
c = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
if (c >= FIRSTNUMBER && c <= LASTNUMBER)
good = POINTS_LETTER;
elif (c >= FIRSTHEAD && c <= LASTHEAD)
good = -(PAIN_HEAD);
elif (c <= LASTOBJECT)
good = (SWORD) object[c].score;
elif (c == FIRSTPROTECTOR + player)
good = POINTS_EMPTY;
elif (c >= FIRSTGLOW && c <= LASTGLOW)
{ if (player == c - FIRSTGLOW)
good = -1;
else good = -(PAIN_GLOW);
} elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
{ good = POINTS_GRAVE;
} elif (c >= FIRSTCHERRY && c <= LASTCHERRY)
{ good = POINTS_CHERRY; // should really be 2x if friendly
} elif (c >= FIRSTFLOWER && c <= LASTFLOWER)
{ good = POINTS_FLOWER; // should really be 2x if friendly
} elif (c >= FIRSTTAIL && c <= LASTTAIL)
{ if (worm[player].armour > 10)
if (player != c - FIRSTTAIL)
good = 2;
else good = 0;
elif (player == c - FIRSTTAIL)
good = -(PAIN_FRIENDLYTAIL);
else good = -(PAIN_ENEMYTAIL);
} else switch(c)
{
case GOLD:
good = POINTS_GOLD;
break;
case SILVER:
good = POINTS_SILVER;
break;
case EMPTY:
good = POINTS_EMPTY;
break;
case DYNAMITE:
good = 1;
break;
case SLIME:
if (worm[player].armour > 0)
good = 0;
else good = -(PAIN_SLIME);
break;
case WOOD:
good = -(PAIN_WOOD * 3);
break;
case STONE:
good = -(PAIN_STONE * 3);
break;
case METAL:
good = -(PAIN_METAL * 3);
break;
case START:
good = POINTS_LETTER * 2;
break;
default:
if (c >= FIRSTCREATURE)
{ if (creature[whichcreature(xwrap(worm[player].x + dirx), ywrap(worm[player].y + diry), c, 255)].player == player)
{ good = creatureinfo[c - FIRSTCREATURE].score;
} elif (creatureinfo[c - FIRSTCREATURE].wall)
{ good = -(PAIN_CREATURE * 2);
} else good = -PAIN_CREATURE;
} else
{ // eg. frost, arrows
good = 0;
}
break;
}
if
( good > bestgood
|| (good == bestgood && dirx == worm[player].deltax && diry == worm[player].deltay)
)
{ bestx = dirx;
besty = diry;
bestgood = good;
} }
if (bestgood < -2 && !arand(1))
{ // turn in any of the 8 directions, or fire
wormqueue
( player,
(SBYTE) ((arand(1) * 2) - 1),
(SBYTE) ((arand(1) * 2) - 1)
);
}
if (bestgood < 0 && !arand(2))
wormqueue(player, 0, 0);
elif (bestx != worm[player].deltax || besty != worm[player].deltay)
wormqueue(player, bestx, besty);
} }
/* remove a keystroke from the worm queue */
if (worm[player].pos != -1)
{ if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
wormbullet(player);
else
{ if (!worm[player].frosted)
{ turnworm(player, thewormqueue[player][0].deltax, thewormqueue[player][0].deltay);
} }
if (--worm[player].pos != -1)
{ for (i = 0; i <= worm[player].pos; i++)
{ thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
} } }
worm[player].frosted = FALSE;
/* move worm */
if (!worm[player].speed)
{ return;
}
if (worm[player].last == FIRSTTAIL + player)
{ field[worm[player].x][worm[player].y] = FIRSTTAIL + player;
index1 = worm[player].olddeltax + 1 + ( (worm[player].olddeltay + 1) * 3);
index2 = bsign(worm[player].deltax) + 1 + ((bsign(worm[player].deltay) + 1) * 3);
drawtail(worm[player].x, worm[player].y, eachtail[player][0][index1][index2]);
} elif (worm[player].last == FIRSTGLOW + player)
{ field[worm[player].x][worm[player].y] = FIRSTGLOW + player;
index1 = worm[player].olddeltax + 1 + ( (worm[player].olddeltay + 1) * 3);
index2 = bsign(worm[player].deltax) + 1 + ((bsign(worm[player].deltay) + 1) * 3);
drawtail(worm[player].x, worm[player].y, eachtail[player][1][index1][index2]);
} else
{ change(worm[player].x, worm[player].y, worm[player].last);
}
worm[player].x = xwrap(worm[player].x + worm[player].deltax);
worm[player].y = ywrap(worm[player].y + worm[player].deltay);
if (worm[player].glow)
{ worm[player].last = FIRSTGLOW + player;
} else
{ worm[player].last = FIRSTTAIL + player;
}
for (i = 0; i <= CREATURES; i++)
{ if
( creature[i].alive
&& creature[i].species == DOG
&& creature[i].dormant > DORMANT
&& creature[i].player == player
)
{ if (!worm[player].rammed)
dogqueue(i, worm[player].deltax, worm[player].deltay);
if (creature[i].dormant < CHASING)
{ creature[i].dormant++;
drawcreature(i);
} } }
/* The deltas are not changed back to the range of -1..1 until after
the dogs have looked at the queue. This enables them to jump properly. */
worm[player].rammed = FALSE;
worm[player].deltax = bsign(worm[player].deltax);
worm[player].deltay = bsign(worm[player].deltay);
worm[player].olddeltax = worm[player].deltax;
worm[player].olddeltay = worm[player].deltay;
/* check for enclosure
#####
#...#
#...# . = interior
#...# # = tail
####! ! = head */
enclosed = FALSE;
for (i = ENCLOSURE_MIN; i <= ENCLOSURE_MAX; i++) // for each size of interior
{ for (j = 0; j <= 3; j++) // four times, once for each direction
{ checkrectangle(j, player, i, i);
if (worm[player].encloser)
{ checkrectangle(j, player, i, i + 1);
checkrectangle(j, player, i + 1, i);
} } }
protectorloop1(player);
// head collision detection
wormcol(player, worm[player].x, worm[player].y);
// draw head
field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
drawhead(player);
updatearrow(worm[player].arrowy);
worm[player].arrowy = worm[player].y;
updatearrow(worm[player].arrowy);
protectorloop2(player);
if (worm[player].cutter)
{ // straight ahead
x = xwrap(worm[player].x + worm[player].deltax);
y = ywrap(worm[player].y + worm[player].deltay);
squareblast(HEAD, player, field[x][y], x, y, TRUE, FALSE);
// left
if (!worm[player].deltax || !worm[player].deltay)
{ // if orthagonal
x = xwrap(worm[player].x + worm[player].deltay);
y = ywrap(worm[player].y - worm[player].deltax);
} else // diagonal
{ if (worm[player].deltax == worm[player].deltay)
{ x = xwrap(worm[player].x + worm[player].deltax);
y = ywrap(worm[player].y - worm[player].deltay);
} else
{ x = xwrap(worm[player].x - worm[player].deltax);
y = ywrap(worm[player].y + worm[player].deltay);
} }
squareblast(HEAD, player, field[x][y], x, y, TRUE, FALSE);
// right
if (!worm[player].deltax || !worm[player].deltay)
{ // if orthagonal
x = xwrap(worm[player].x - worm[player].deltay);
y = ywrap(worm[player].y + worm[player].deltax);
} else // diagonal
{ if (worm[player].deltax == worm[player].deltay)
{ x = xwrap(worm[player].x - worm[player].deltax);
y = ywrap(worm[player].y + worm[player].deltay);
} else
{ x = xwrap(worm[player].x + worm[player].deltax);
y = ywrap(worm[player].y - worm[player].deltay);
} }
squareblast(HEAD, player, field[x][y], x, y, TRUE, FALSE);
// ahead left
if (!worm[player].deltax || !worm[player].deltay)
{ // if orthagonal
if (worm[player].deltax) // if east or west
{ x = xwrap(worm[player].x + worm[player].deltax);
y = ywrap(worm[player].y - worm[player].deltax);
} else // north or south
{ x = xwrap(worm[player].x + worm[player].deltay);
y = ywrap(worm[player].y + worm[player].deltay);
} }
else // diagonal
{ if (worm[player].deltax == worm[player].deltay)
{ x = xwrap(worm[player].x + worm[player].deltax);
y = worm[player].y;
} else
{ x = worm[player].x;
y = ywrap(worm[player].y + worm[player].deltay);
} }
squareblast(HEAD, player, field[x][y], x, y, TRUE, FALSE);
// ahead right
if (!worm[player].deltax || !worm[player].deltay)
{ // if orthagonal
if (worm[player].deltax) // if east or west
{ x = xwrap(worm[player].x + worm[player].deltax);;
y = ywrap(worm[player].y + worm[player].deltax);
} else // north or south
{ x = xwrap(worm[player].x - worm[player].deltay);
y = ywrap(worm[player].y + worm[player].deltay);
} }
else // diagonal
{ if (worm[player].deltax == worm[player].deltay)
{ x = worm[player].x;
y = ywrap(worm[player].y + worm[player].deltay);
} else
{ x = xwrap(worm[player].x + worm[player].deltax);
y = worm[player].y;
} }
squareblast(HEAD, player, field[x][y], x, y, TRUE, FALSE);
} }
MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot)
{ UBYTE c = field[x][y];
SBYTE i;
if (c == EMPTY)
{ ;
} elif (c >= FIRSTHEAD && c <= LASTHEAD)
{ protworm(x, y, player, c - FIRSTHEAD);
} elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
{ protprot(x, y, player, c - FIRSTPROTECTOR);
} elif (c >= FIRSTTAIL && c <= LASTTAIL)
{ if (player == c - FIRSTTAIL)
{ protector[player][thisprot].visible = FALSE;
} }
elif
( c == STONE
|| c == WOOD
|| c == METAL
|| c == TELEPORT
|| c == FIRSTGLOW + player
|| c == START
)
{ protector[player][thisprot].visible = FALSE;
} elif (c >= FIRSTCREATURE)
{ i = whichcreature(x, y, c, 255);
protcreature(player, i);
} else
{ bothcol(player, x, y);
} }
AGLOBAL void bothcol(SBYTE player, SBYTE x, SBYTE y)
{ UBYTE c = field[x][y], i;
if (c >= FIRSTNUMBER && c <= LASTNUMBER)
{ if (!(getnumber(player)))
{ putnumber();
} }
elif (c >= FIRSTFLOWER && c <= LASTFLOWER)
{ effect(FXGET_GRAVE);
if (player == c - FIRSTFLOWER)
{ wormscore(player, POINTS_FLOWER * 2);
} else
{ wormscore(player, POINTS_FLOWER);
}
if (level != 0)
{ getnumber(player);
change(numberx, numbery, FIRSTNUMBER + number - 1);
updatearrow(numbery);
} }
elif (c >= FIRSTCHERRY && c <= LASTCHERRY)
{ effect(FXGET_GRAVE);
if (player == c - FIRSTCHERRY)
{ wormscore(player, POINTS_CHERRY * 2);
} else
{ wormscore(player, POINTS_CHERRY);
} }
elif (c <= LASTOBJECT)
{ wormscore(player, wormobject(player, x, y));
} elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
{ effect(FXGET_GRAVE);
wormscore(player, POINTS_GRAVE);
worm[player].multi *= worm[c - FIRSTGRAVE].multi;
if (worm[player].multi > 1)
{ if (worm[player].multi > MULTILIMIT)
worm[player].multi = MULTILIMIT;
}
worm[player].power += worm[c - FIRSTGRAVE].power;
if (worm[player].power > 1)
{ if (worm[player].power > POWERLIMIT)
worm[player].power = POWERLIMIT;
stat(player, POWER);
worm[c - FIRSTGRAVE].power = 0;
stat(c - FIRSTGRAVE, POWER);
}
worm[player].ammo += worm[c - FIRSTGRAVE].ammo;
if (worm[player].ammo > 0)
{ if (worm[player].ammo > AMMOLIMIT)
worm[player].ammo = AMMOLIMIT;
stat(player, AMMO);
worm[c - FIRSTGRAVE].ammo = 0;
stat(c - FIRSTGRAVE, AMMO);
}
if (worm[c - FIRSTGRAVE].brakes)
{ worm[player].brakes = TRUE;
stat(player, BRAKES);
worm[c - FIRSTGRAVE].brakes = FALSE;
worm[c - FIRSTGRAVE].speed = NORMAL;
stat(c - FIRSTGRAVE, BRAKES);
}
if (worm[c - FIRSTGRAVE].affixer)
{ worm[player].affixer = TRUE;
worm[c - FIRSTGRAVE].affixer = FALSE;
}
if (worm[c - FIRSTGRAVE].remnants)
{ worm[player].remnants = TRUE;
worm[c - FIRSTGRAVE].remnants = FALSE;
}
if (worm[c - FIRSTGRAVE].sideshot)
{ worm[player].sideshot = TRUE;
worm[c - FIRSTGRAVE].sideshot = FALSE;
}
if (worm[c - FIRSTGRAVE].pusher)
{ worm[player].pusher = TRUE;
worm[c - FIRSTGRAVE].pusher = FALSE;
}
if (worm[c - FIRSTGRAVE].encloser)
{ worm[player].encloser = TRUE;
worm[c - FIRSTGRAVE].encloser = FALSE;
}
if (worm[c - FIRSTGRAVE].autojump)
{ worm[player].autojump = TRUE;
worm[c - FIRSTGRAVE].autojump = FALSE;
}
if (worm[c - FIRSTGRAVE].armour)
{ worm[player].armour += worm[c - FIRSTGRAVE].armour;
if (worm[player].armour > ARMOURLIMIT)
worm[player].armour = ARMOURLIMIT;
worm[c - FIRSTGRAVE].armour = 0;
}
if (worm[c - FIRSTGRAVE].glow)
{ worm[player].glow += worm[c - FIRSTGRAVE].glow;
if (worm[player].glow > GLOWLIMIT)
worm[player].glow = GLOWLIMIT;
worm[c - FIRSTGRAVE].glow = 0;
}
if (worm[c - FIRSTGRAVE].cutter)
{ worm[player].cutter += worm[c - FIRSTGRAVE].cutter;
if (worm[player].armour > CUTTERLIMIT)
worm[player].armour = CUTTERLIMIT;
worm[c - FIRSTGRAVE].cutter = 0;
}
for (i = 0; i <= LASTOBJECT; i++)
{ icon(player, i);
icon(c - FIRSTGRAVE, i);
} }
else
{ switch(c)
{
case SILVER:
wormscore(player, POINTS_SILVER);
break;
case GOLD:
wormscore(player, POINTS_GOLD);
break;
case DYNAMITE:
effect(FXUSE_BOMB);
banging = TRUE;
bangdynamite(x, y, player);
break;
default:
break;
} } }
MODULE void wormbullet(SBYTE player)
{ ABOOL finished,
numbered = FALSE;
FLAG final;
SBYTE distance,
i, j,
x, y;
UBYTE c;
if (!worm[player].ammo)
{ stat(player, BONUS); // why?
if (worm[player].speed == FAST)
distance = DISTANCE_FAST;
elif (worm[player].speed == NORMAL)
distance = DISTANCE_NORMAL;
else
{ // assert(worm[player].speed == SLOW);
distance = DISTANCE_SLOW;
}
// assert(abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1);
x = xwrap(worm[player].x + (worm[player].deltax * distance));
y = ywrap(worm[player].y + (worm[player].deltay * distance));
c = field[x][y];
if
( (c < FIRSTGLOW || c > LASTGLOW || player != c - FIRSTGLOW)
&& (!blockedsquare(x, y))
)
{ worm[player].deltax *= distance;
worm[player].deltay *= distance;
} }
else
{ effect(FXUSE_AMMO);
worm[player].ammo--;
stat(player, AMMO);
if (worm[player].sideshot)
{ bullet[7].alive = bullet[8].alive = TRUE;
bullet[7].teleported = bullet[8].teleported = 0;
bullet[7].visible = bullet[8].visible = TRUE;
bullet[7].reflected = bullet[8].reflected = FALSE;
if (!worm[player].deltax && worm[player].deltay)
{ bullet[7].deltax = -1;
bullet[8].deltax = 1;
bullet[7].deltay = bullet[8].deltay = 0;
} elif (worm[player].deltax && !worm[player].deltay)
{ bullet[7].deltax = bullet[8].deltax = 0;
bullet[7].deltay = -1;
bullet[8].deltay = 1;
} else /* worm is diagonal */
{ if (worm[player].deltax == worm[player].deltay)
{ bullet[7].deltax = 1;
bullet[7].deltay = -1;
} else
{ bullet[7].deltax = -1;
bullet[7].deltay = -1;
}
bullet[8].deltax = -bullet[7].deltax;
bullet[8].deltay = -bullet[7].deltay;
}
bullet[7].x = worm[player].x + bullet[7].deltax;
bullet[7].y = worm[player].y + bullet[7].deltay;
bullet[8].x = worm[player].x + bullet[8].deltax;
bullet[8].y = worm[player].y + bullet[8].deltay;
}
for (i = 0; i <= worm[player].power; i++)
{ bullet[i].alive = TRUE;
bullet[i].teleported = 0;
bullet[i].visible = TRUE;
bullet[i].reflected = FALSE;
bullet[i].deltax = worm[player].deltax;
bullet[i].deltay = worm[player].deltay;
if (i % 2 == 0)
distance = i / 2;
else distance = -((i + 1) / 2);
if (worm[player].deltax == 0)
{ bullet[i].x = worm[player].x + distance;
bullet[i].y = worm[player].y + worm[player].deltay;
} elif (worm[player].deltay == 0)
{ bullet[i].x = worm[player].x + worm[player].deltax;
bullet[i].y = worm[player].y + distance;
} else
{ switch (i)
{
case 0:
bullet[i].x = worm[player].x + worm[player].deltax;
bullet[i].y = worm[player].y + worm[player].deltay;
break;
case 1:
bullet[i].x = worm[player].x + worm[player].deltax;
bullet[i].y = worm[player].y;
break;
case 2:
bullet[i].x = worm[player].x;
bullet[i].y = worm[player].y + worm[player].deltay;
break;
case 3:
bullet[i].x = worm[player].x + worm[player].deltax * 2;
bullet[i].y = worm[player].y;
break;
case 4:
bullet[i].x = worm[player].x;
bullet[i].y = worm[player].y + worm[player].deltay * 2;
break;
case 5:
bullet[i].x = worm[player].x + worm[player].deltax * 2;
bullet[i].y = worm[player].y - worm[player].deltay;
break;
case 6:
bullet[i].x = worm[player].x - worm[player].deltax;
bullet[i].y = worm[player].y + worm[player].deltay * 2;
break;
default:
break;
} } }
for (i = 0; i <= 8; i++)
{ if (bullet[i].alive && (!valid(bullet[i].x, bullet[i].y)))
{ bullet[i].alive = FALSE;
} }
/* Bullets are now set up. */
finished = FALSE;
while (!finished)
{ finished = TRUE;
for (i = 0; i <= 8; i++)
{ if (bullet[i].alive)
{ if (bullet[i].visible)
{ if (worm[player].remnants)
change(bullet[i].x, bullet[i].y, FIRSTGLOW + player);
else change(bullet[i].x, bullet[i].y, EMPTY);
}
finished = FALSE;
bullet[i].visible = TRUE;
if (bullet[i].reflected)
{ bullet[i].x -= bullet[i].deltax;
bullet[i].y -= bullet[i].deltay;
} else
{ bullet[i].x += bullet[i].deltax;
bullet[i].y += bullet[i].deltay;
}
x = bullet[i].x;
y = bullet[i].y;
c = field[x][y];
if (!(valid(x, y)))
bullet[i].alive = FALSE;
elif (x == worm[player].x && y == worm[player].y)
{ /* hit by own bullet */
bullet[i].alive = FALSE;
if (worm[player].armour == 0)
{ worm[player].cause = FIRSTFIRE + player;
worm[player].victor = -1;
worm[player].alive = FALSE;
} }
elif (c >= FIRSTHEAD && c <= LASTHEAD)
{ if (worm[c - FIRSTHEAD].armour == 0)
{ worm[c - FIRSTHEAD].cause = FIRSTFIRE + player;
worm[c - FIRSTHEAD].victor = player;
worm[c - FIRSTHEAD].alive = FALSE;
} else effect(FXUSE_ARMOUR);
bullet[i].alive = FALSE;
} elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
{ if (player != c - FIRSTPROTECTOR)
{ effect(FXBORN_PROTECTOR);
bullet[i].alive = FALSE;
} else bullet[i].visible = FALSE;
} elif (c >= FIRSTNUMBER && c <= LASTNUMBER)
{ final = getnumber(player);
numbered = TRUE;
} elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
{ bullet[i].alive = FALSE;
} else
{ switch(c)
{
case MINIBOMB:
// sets it off, for your benefit
bullet[i].alive = FALSE;
bombblast(HEAD, player, x, y, FALSE);
break;
case SUPERBOMB:
// sets it off, for your benefit
bullet[i].alive = FALSE;
bombblast(HEAD, player, x, y, TRUE);
break;
case SLIME:
case WOOD:
// destroys one layer of it
bullet[i].alive = FALSE;
change(x, y, EMPTY);
break;
case METAL:
if (bullet[i].reflected)
bullet[i].alive = FALSE;
else
{ bullet[i].reflected = TRUE;
bullet[i].x -= bullet[i].deltax * 2;
bullet[i].y -= bullet[i].deltay * 2;
}
break;
case STONE:
case START:
bullet[i].alive = FALSE;
break;
case TELEPORT:
j = whichteleport(bullet[i].x, bullet[i].y);
if (bullet[i].teleported == 2 || blockedtel(j, bullet[i].deltax, bullet[i].deltay))
{ bullet[i].alive = FALSE;
} else
{ effect(FXUSE_TELEPORT);
bullet[i].visible = FALSE;
bullet[i].teleported++;
bullet[i].x = teleport[partner(j)].x;
bullet[i].y = teleport[partner(j)].y;
}
break;
default:
if (c >= FIRSTCREATURE)
{ j = whichcreature(x, y, c, 255);
bullet[i].alive = FALSE;
wormkillcreature(player, j, TRUE);
change(x, y, FIRSTFLOWER + player);
} elif (c <= LASTOBJECT)
{ bullet[i].alive = FALSE;
change(x, y, FIRSTCHERRY + player);
}
break;
} }
// x and y need this refreshing here
x = bullet[i].x;
y = bullet[i].y;
if (bullet[i].alive && bullet[i].visible)
{ draw(x, y, FIRSTFIRE + player);
} } } }
if (numbered && !final)
{ putnumber();
}
clearkybd();
} }
MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay)
{ if (creature[which].pos < DOGQUEUELIMIT)
{ creature[which].pos++;
thedogqueue[which][creature[which].pos].deltax = deltax;
thedogqueue[which][creature[which].pos].deltay = deltay;
} else
{ creature[which].alive = FALSE;
change(creature[which].x, creature[which].y, EMPTY);
} }
/* NAME queue -- adds a keystroke to the key queue
SYNOPSIS name(SBYTE, SBYTE, SBYTE);
FUNCTION Adds a keystroke to the in-game key queue.
INPUTS player - player that pressed the key
deltax - the deltax of the key
deltay - the deltay of the key
IMPLEMENTATION
thewormqueue[] array has WORMQUEUELIMIT as its last index.
It is implemented as a FIFO stack rather than LIFO so that
the keystrokes are processed in the correct order (that is,
the order in which they were pressed). The oldest keystroke
is always at index [0], the next oldest at [1], and so on
upwards to the newest keystroke, at [worm[player].pos].
Keystrokes are removed from the bottom of the array ([0]),
and the rest of the array is shuffled down to fill the gap,
so that the contents of [1] go to [0], the contents of [2]
go to [1], etc. worm[player].pos is adjusted to always point
to the newest entry, which is the 'end' of the queue.
MODULE engine2.c */
AGLOBAL void wormqueue(SBYTE player, SBYTE deltax, SBYTE deltay)
{ if (worm[player].pos < WORMQUEUELIMIT)
{ worm[player].pos++;
thewormqueue[player][worm[player].pos].deltax = deltax;
thewormqueue[player][worm[player].pos].deltay = deltay;
} }
AGLOBAL void drawcreature(UBYTE which)
{ switch(creature[which].species)
{
case BIRD:
draw(creature[which].x, creature[which].y, birdframes[creature[which].frame]);
break;
case BULL:
if (creature[which].dir == -1)
{ draw(creature[which].x, creature[which].y, BULLLEFT);
} else
{ // assert(creature[which].dir == 1);
draw(creature[which].x, creature[which].y, BULLRIGHT);
}
break;
case RABBIT:
if (creature[which].deltax == -1)
{ draw(creature[which].x, creature[which].y, RABBITLEFT);
} else
{ // assert(creature[which].deltax == 1);
draw(creature[which].x, creature[which].y, RABBITRIGHT);
}
break;
case DOG:
if (creature[which].dormant == 0)
{ draw(creature[which].x, creature[which].y, DOGDORMANT);
} elif (creature[which].dormant < CHASING)
{ draw(creature[which].x, creature[which].y, DOGAWAKENING);
} else
{ draw(creature[which].x, creature[which].y, DOGCHASING);
}
break;
case RAIN:
draw(creature[which].x, creature[which].y, FIRSTRAIN + creature[which].player);
break;
case FRAGMENT:
if (creature[which].subspecies == FRAGMENT)
{ draw(creature[which].x, creature[which].y, FRAGMENT);
} else
{ // assert(creature[which].subspecies == BANANA);
draw(creature[which].x, creature[which].y, bananaframes[creature[which].player][creature[which].frame]);
}
break;
case FROG:
if (creature[which].dir == -1)
{ draw(creature[which].x, creature[which].y, FROGLEFT);
} else
{ // assert(creature[which].dir == 1);
draw(creature[which].x, creature[which].y, FROGRIGHT);
}
break;
case MISSILE_C:
draw(creature[which].x, creature[which].y, missileframes[creature[which].player][creature[which].frame]);
break;
default:
draw(creature[which].x, creature[which].y, creature[which].species);
break;
}
field[creature[which].x][creature[which].y] = creature[which].species;
}
AGLOBAL ABOOL blockedsquare(SBYTE x, SBYTE y)
{ UBYTE c = field[x][y];
if
( c == STONE
|| c == METAL
|| c == WOOD
|| (c >= FIRSTCREATURE && creatureinfo[c - FIRSTCREATURE].wall)
)
{ return TRUE;
} else
{ return FALSE;
} }
MODULE void choosediagonal(UBYTE which)
{ SBYTE number;
/* This routine is a workaround for a very strange bug. */
do
{ number = arand(3);
switch(number)
{
case 0:
creature[which].deltax = -1;
creature[which].deltay = -1;
break;
case 1:
creature[which].deltax = -1;
creature[which].deltay = 1;
break;
case 2:
creature[which].deltax = 1;
creature[which].deltay = -1;
break;
case 3:
creature[which].deltax = 1;
creature[which].deltay = 1;
break;
default:
// assert(0);
break;
} // end switch
} while (!valid(creature[which].x + creature[which].deltax, creature[which].y + creature[which].deltay));
}
MODULE void chooseorthagonal(SBYTE* xx, SBYTE* yy)
{ SBYTE number;
/* This routine is a workaround for a very strange bug. */
number = arand(3);
switch(number)
{
case 0:
*xx = 0;
*yy = -1;
break;
case 1:
*xx = 0;
*yy = 1;
break;
case 2:
*xx = -1;
*yy = 0;
break;
case 3:
*xx = 1;
*yy = 0;
break;
default:
// assert(0);
break;
} }
AGLOBAL void stoppedwormloop(SBYTE player)
{ SBYTE i;
FLAG go = FALSE;
/* remove a keystroke from the worm queue
The worm still has deltax and deltay whilst stopped. */
if (!(r % SPEED_PROTECTOR))
{ protectorloop1(player);
protectorloop2(player);
} // affixer becomes a disadvantage in this situation
if (worm[player].pos != -1)
{ if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
{ if (worm[player].ammo)
{ wormbullet(player); // you can fire bullets whilst stopped :-)
} }
elif
( thewormqueue[player][0].deltax != -worm[player].deltax
|| thewormqueue[player][0].deltay != -worm[player].deltay
)
{ worm[player].speed = SLOW;
stat(player, BRAKES);
worm[player].deltax = thewormqueue[player][0].deltax;
worm[player].deltay = thewormqueue[player][0].deltay;
worm[player].frosted = FALSE;
go = TRUE;
}
if (--worm[player].pos != -1)
{ for (i = 0; i <= worm[player].pos; i++)
{ thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
} }
if (go)
{ wormloop(player);
worm[player].wait = TRUE;
} } }
MODULE void protectorloop1(SBYTE player)
{ SBYTE i;
// move protectors
for (i = 0; i <= PROTECTORS; i++)
{ if (protector[player][i].alive)
{ if (protector[player][i].visible)
{ change(protector[player][i].x, protector[player][i].y, protector[player][i].last);
} else protector[player][i].visible = TRUE;
protector[player][i].last = EMPTY;
if (i == NOSE)
{ protector[player][i].relx = worm[player].deltax * DISTANCE_NOSE;
protector[player][i].rely = worm[player].deltay * DISTANCE_NOSE;
if (!worm[player].affixer)
{ if (worm[player].position == -1)
worm[player].posidir = 1;
elif (worm[player].position == 1)
worm[player].posidir = -1;
worm[player].position += worm[player].posidir;
if (worm[player].deltax == 0)
protector[player][i].relx = worm[player].position;
elif (worm[player].deltay == 0)
protector[player][i].rely = worm[player].position;
elif (worm[player].position == -1)
protector[player][i].relx = worm[player].deltax * (DISTANCE_NOSE - 1);
elif (worm[player].position == 1)
protector[player][i].rely = worm[player].deltay * (DISTANCE_NOSE - 1);
} }
elif (!worm[player].affixer)
{ if (protector[player][i].relx == 1 && protector[player][i].rely == -1)
{ protector[player][i].deltax = 0;
protector[player][i].deltay = 1;
} elif (protector[player][i].relx == 1 && protector[player][i].rely == 1)
{ protector[player][i].deltax = -1;
protector[player][i].deltay = 0;
} elif (protector[player][i].relx == -1 && protector[player][i].rely == 1)
{ protector[player][i].deltax = 0;
protector[player][i].deltay = -1;
} elif (protector[player][i].relx == -1 && protector[player][i].rely == -1)
{ protector[player][i].deltax = 1;
protector[player][i].deltay = 0;
}
protector[player][i].relx += protector[player][i].deltax;
protector[player][i].rely += protector[player][i].deltay;
}
protector[player][i].x = worm[player].x + protector[player][i].relx;
protector[player][i].y = worm[player].y + protector[player][i].rely;
if (!valid(protector[player][i].x, protector[player][i].y))
{ protector[player][i].visible = FALSE;
} } } }
MODULE void protectorloop2(SBYTE player)
{ SBYTE thisprot;
// protector collision detection
for (thisprot = 0; thisprot <= PROTECTORS; thisprot++)
{ if (protector[player][thisprot].alive && protector[player][thisprot].visible)
{ protcol(player, protector[player][thisprot].x, protector[player][thisprot].y, thisprot);
// we now need to recheck whether the protector should be visible or not
// this might be defensive programming to hide a bug, or might be legitimate
if (!valid(protector[player][thisprot].x, protector[player][thisprot].y))
{ protector[player][thisprot].visible = FALSE;
}
// draw protector
if (protector[player][thisprot].alive && protector[player][thisprot].visible) // in case protector has just been killed, etc.
{ change(protector[player][thisprot].x, protector[player][thisprot].y, FIRSTPROTECTOR + player);
} } } }
MODULE void turncreature(UBYTE which)
{ switch(creature[which].dir)
{ case 0:
creature[which].deltax = 0;
creature[which].deltay = -1;
break;
case 1:
creature[which].deltax = 1;
creature[which].deltay = -1;
break;
case 2:
creature[which].deltax = 1;
creature[which].deltay = 0;
break;
case 3:
creature[which].deltax = 1;
creature[which].deltay = 1;
break;
case 4:
creature[which].deltax = 0;
creature[which].deltay = 1;
break;
case 5:
creature[which].deltax = -1;
creature[which].deltay = 1;
break;
case 6:
creature[which].deltax = -1;
creature[which].deltay = 0;
break;
case 7:
creature[which].deltax = -1;
creature[which].deltay = -1;
break;
default:
// assert(0);
creature[which].deltax = creature[which].deltay = 0; // to avoid spurious warnings
break;
}
}